package io.kiki.sba.registry.common.model;


import io.kiki.sba.registry.common.model.store.BaseInfo;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang.StringUtils;

import java.util.*;

@Setter
@Getter
public final class DataUtils {

    private DataUtils() {
    }

    /**
     * instanceId/group/app - {info.count,dataInfoId.count}
     */
    public static <T extends BaseInfo> Map<String, Map<String, Map<String, Tuple<Integer, Integer>>>> countGroupByInstanceIdGroupApp(Collection<T> infos) {
        Map<String, Map<String, Map<String, List<T>>>> groupBys = new HashMap<>();
        for (T info : infos) {
            Map<String, Map<String, List<T>>> groupCount = groupBys.computeIfAbsent(info.getInstanceId(), k -> new HashMap<>());
            Map<String, List<T>> appCount = groupCount.computeIfAbsent(InterestGroup.normalizeGroup(info.getGroup()), k -> new HashMap<>());
            String appName = info.getAppName();
            if (StringUtils.isBlank(appName)) {
                appName = "";
            }
            List<T> list = appCount.computeIfAbsent(appName, k -> new ArrayList<>());
            list.add(info);
        }
        Map<String, Map<String, Map<String, Tuple<Integer, Integer>>>> ret = new HashMap<>();
        for (Map.Entry<String, Map<String, Map<String, List<T>>>> count : groupBys.entrySet()) {
            final String instanceId = count.getKey();
            Map<String, Map<String, Tuple<Integer, Integer>>> instanceCount = ret.computeIfAbsent(instanceId, k -> new HashMap<>());
            for (Map.Entry<String, Map<String, List<T>>> e : count.getValue().entrySet()) {
                final String group = e.getKey();
                Map<String, Tuple<Integer, Integer>> groupCount = instanceCount.computeIfAbsent(group, k -> new HashMap<>());
                for (Map.Entry<String, List<T>> apps : e.getValue().entrySet()) {
                    List<T> list = apps.getValue();
                    final int infoCount = list.size();
                    Set<String> dataInfoIds = new HashSet<>(64);
                    for (T t : list) {
                        dataInfoIds.add(t.getDataInfoId());
                    }
                    final int dataInfoIdCount = dataInfoIds.size();
                    groupCount.put(apps.getKey(), Tuple.of(infoCount, dataInfoIdCount));
                }
            }
        }
        return ret;
    }

    /**
     * instanceId/group - {info.count,dataInfoId.count}
     */
    public static <T extends BaseInfo> Map<String, Map<String, Tuple<Integer, Integer>>> countGroupByInstanceIdGroup(Collection<T> infos) {

        Map<String, Map<String, List<T>>> groupBys = new HashMap<>();
        for (T info : infos) {
            Map<String, List<T>> groupCount = groupBys.computeIfAbsent(info.getInstanceId(), k -> new HashMap<>());
            List<T> infoList = groupCount.computeIfAbsent(InterestGroup.normalizeGroup(info.getGroup()), k -> new ArrayList<>());
            infoList.add(info);
        }
        Map<String, Map<String, Tuple<Integer, Integer>>> ret = new HashMap<>();
        for (Map.Entry<String, Map<String, List<T>>> instances : groupBys.entrySet()) {
            final String instanceId = instances.getKey();
            for (Map.Entry<String, List<T>> groups : instances.getValue().entrySet()) {
                final String group = groups.getKey();
                List<T> list = groups.getValue();
                final int infoCount = list.size();
                Set<String> dataInfoIds = new HashSet<>(256);
                for (T t : list) {
                    dataInfoIds.add(t.getDataInfoId());
                }
                final int dataInfoIdCount = dataInfoIds.size();
                Map<String, Tuple<Integer, Integer>> groupCount = ret.computeIfAbsent(instanceId, k -> new HashMap<>());
                groupCount.put(group, Tuple.of(infoCount, dataInfoIdCount));
            }
        }
        return ret;
    }
}
